'use strict'
const path = require('path')
const defaultSettings = require('./src/settings.js')

function resolve(dir) {
   return path.join(__dirname, dir)
}

const name = defaultSettings.title || 'vue Admin Template' // page title

// If your port is set to 80,
// use administrator privileges to execute the command line.
// For example, Mac: sudo npm run
// You can change the port by the following methods:
// port = 9528 npm run dev OR npm run dev --port = 9528
// process.env.port实际上是一个nodejs服务下的环境变量
// development => 开发环境
// production => 生产环境
// 当我们运行npm run dev进行开发调试的时候,此时会加载执行.env.development文件内容
// 当我们运行npm run build:prod进行生产环境打包的时候,会加载执行.env.production文件内容
// 改端口号直接在.env.development文件 写入对于port变量的赋值即可
const port = process.env.port || process.env.npm_config_port || 9528 // dev port

// 排除后引入 cdn 中的变量
// 这时的配置实际上是对开发环境和生产环境都生效的，在开发环境时，
// 没有必要使用CDN，此时我们可以使用环境变量来进行区分
let cdn = { css: [], js: [] }
let externals = {}
// 判断是否是生产环境
const isProd = process.env.NODE_ENV === 'production'
// 只有生产环境才有必要去做排除 和 CDN 的注入
if (isProd) {
   externals = {
      'element-ui': 'ELEMENT',
      'xlsx': 'XLSX',
      'vue': 'Vue'
   }
   cdn = {
      // 样式表
      css: [
         // element-ui css
         'https://unpkg.com/element-ui/lib/theme-chalk/index.css'
      ],
      js: [
         // vue must at first!
         // vue js 必须放到首位
         'https://unpkg.com/vue/dist/vue.js', // vuejs
         // element-ui js
         'https://unpkg.com/element-ui/lib/index.js', // elementUI
         'https://cdn.jsdelivr.net/npm/xlsx@0.16.6/dist/jszip.min.js',
         'https://cdn.jsdelivr.net/npm/xlsx@0.16.6/dist/xlsx.full.min.js'
      ]
   }
}

// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
   /**
    * You will need to set publicPath if you plan to deploy your site under a sub path,
    * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
    * then publicPath should be set to "/bar/".
    * In most cases please use '/' !!!
    * Detail: https://cli.vuejs.org/config/#publicpath
    */
   publicPath: '/',
   outputDir: 'dist',
   assetsDir: 'static',
   // 环境变量：
   // process.env.NODE_ENV # 当为production时为生产环境
   // 为development时为开发环境
   lintOnSave: process.env.NODE_ENV === 'development',
   productionSourceMap: false,
   devServer: {
      port: port,
      open: true,
      overlay: {
         warnings: false,
         errors: true
      },
      //  配置反向代理
      proxy: {
         // 代理时，需要 /api 所以不要干掉
         '/api': {
            // 要代理的服务器地址，这里不需要写 api，
            // 因为所有的请求头的基地址都加了/ api
            target: 'http://ihrm-java.itheima.net/',
            // 开启跨域
            changeOrigin: true
         }
      }
      //  before: require('./mock/mock-server.js')
   },
   // 配置 webpack 的属性
   configureWebpack: {
      // provide the app's title in webpack's name field, so that
      // it can be accessed in index.html to inject the correct title.
      name: name,
      resolve: {
         alias: {
            '@': resolve('src')
         }
      },
      // 表示要排除的包名

      // key(要排除的包名): value(实际上是实际引入的包的全局的变量名)
      // 因为要排除 elementUI,所以后面要引入CDN文件，
      // CDN文件里边有 elementUI 的全局变量名
      // 首先把 elementUI 排除了，所以说你肯定要引入 CDN 的 elementUI,
      // 引入的 CDN 的 elementUI 是一个 js 文件，里边有一个全局变量，全局变量叫 ELEMENT
      // 全局变量在 CDN 的 js 文件中的 elementUI 中叫 ELEMENT
      // 实际上就要用这个 ELEMENT 作为我的 value 值
      // 首先会把这三个包给排除掉，然后排除的位置，用 value 这个变量来替换给占上位置了
      // 这三个变量是通过 js 引入的全局变量
      
      // 打包完之后，所有的导入的 js 会集中在一个 js 文件夹中，有一个总文件，还有其他按需加载进来的文件
      externals: externals
   },
   // webpack 的执行链
   chainWebpack(config) {
      // it can improve the speed of the first screen, it is recommended to turn on preload
      config.plugin('preload').tap(() => [
         {
            rel: 'preload',
            // to ignore runtime.js
            // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
            fileBlacklist: [
               /\.map$/,
               /hot-update\.js$/,
               /runtime\..*\.js$/
            ],
            include: 'initial'
         }
      ])

      // 注入 CDN 变量
      // 通过 html-webpack-plugin 这个插件注入到 index.html之中: 注入 cdn 的变量
      // 这行代码 会在我们执行打包的时候执行，就会将 cdn 变量注入到 html 模板中
      // 这个cdn变量是一个对象，我们要的是里边的css 跟 js，也就是说我在打包的时候实际上
      // 给了我的html文件里在打包过程中，加了一个cdn，要引入它的css跟js
      // config 就是webpack 的配置文件
      config.plugin('html').tap(args => {
         // args 是注入 html 模板的一个变量
         // 后面的 cdn 就是上边定义的变量
         //  args 的第零个对象，给他赋值了一个cdn 的属性
         // 注入到编译环境的cdn
         // cdn 又会在编译的时候 ， index.html 中，在打包的时候回去执行
         // 执行的时候会拿到 cdn 的变量，拿到之后循环生成 link 跟 script 标签
         // 这样即排除了打包，又把 cdn 文件引进去了，这就是性能的优化
         // 最大化减轻业务代码的压力
         args[0].cdn = cdn
         // 需要返回这个参数
         return args
      })

      // when there are many pages, it will cause too many meaningless requests
      config.plugins.delete('prefetch')

      // set svg-sprite-loader
      config.module
         .rule('svg')
         .exclude.add(resolve('src/icons'))
         .end()
      config.module
         .rule('icons')
         .test(/\.svg$/)
         .include.add(resolve('src/icons'))
         .end()
         .use('svg-sprite-loader')
         .loader('svg-sprite-loader')
         .options({
            symbolId: 'icon-[name]'
         })
         .end()

      config.when(process.env.NODE_ENV !== 'development', config => {
         config
            .plugin('ScriptExtHtmlWebpackPlugin')
            .after('html')
            .use('script-ext-html-webpack-plugin', [
               {
                  // `runtime` must same as runtimeChunk name. default is `runtime`
                  inline: /runtime\..*\.js$/
               }
            ])
            .end()
         config.optimization.splitChunks({
            chunks: 'all',
            cacheGroups: {
               libs: {
                  name: 'chunk-libs',
                  test: /[\\/]node_modules[\\/]/,
                  priority: 10,
                  chunks: 'initial' // only package third parties that are initially dependent
               },
               elementUI: {
                  name: 'chunk-elementUI', // split elementUI into a single package
                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
               },
               commons: {
                  name: 'chunk-commons',
                  test: resolve('src/components'), // can customize your rules
                  minChunks: 3, //  minimum common number
                  priority: 5,
                  reuseExistingChunk: true
               }
            }
         })
         // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
         config.optimization.runtimeChunk('single')
      })
   }
}
